/* ESPNOW Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

/*
   This example shows how to use ESPNOW.
   Prepare two device, one for sending ESPNOW data and another for receiving
   ESPNOW data.
*/
#include "esp_crc.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_mac.h"
#include "esp_netif.h"
#include "esp_now.h"
#include "esp_random.h"
#include "esp_wifi.h"
#include "espnow_example.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/timers.h"
#include "nvs_flash.h"
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "driver/ledc.h"

#define ESPNOW_MAXDELAY 512

static const char *TAG = "espnow_example";

static QueueHandle_t s_example_espnow_queue;
typedef struct {
  uint32_t magic;
  size_t size;
  uint8_t desc_mac[6];
  uint8_t data[230];
} espnow_recv_data_t;

static uint8_t root_mac[ESP_NOW_ETH_ALEN] = {0x3c, 0x84, 0x27,
                                             0xc9, 0xa5, 0x1d};
static uint8_t node_mac[ESP_NOW_ETH_ALEN] = {0x24, 0xec, 0x4a,
                                             0x27, 0x16, 0x2c};
// static uint8_t node_mac[ESP_NOW_ETH_ALEN] = {0x54, 0x32, 0x04,
//                                              0x0b, 0x4a, 0xb0};
static uint8_t local_node_mac[ESP_NOW_ETH_ALEN] = {0};

static void example_espnow_deinit(example_espnow_send_param_t *send_param);

/* WiFi should start before using ESPNOW */
static void example_wifi_init(void) {
  ESP_ERROR_CHECK(esp_netif_init());
  ESP_ERROR_CHECK(esp_event_loop_create_default());
  wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
  ESP_ERROR_CHECK(esp_wifi_init(&cfg));

  ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
  ESP_ERROR_CHECK(esp_wifi_set_mode(ESPNOW_WIFI_MODE));
  ESP_ERROR_CHECK(esp_wifi_start());
  ESP_ERROR_CHECK(
      esp_wifi_set_channel(CONFIG_ESPNOW_CHANNEL, WIFI_SECOND_CHAN_NONE));

  ESP_ERROR_CHECK(esp_wifi_set_protocol(
      ESPNOW_WIFI_IF, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G |
                          WIFI_PROTOCOL_11N | WIFI_PROTOCOL_LR));
}

static void example_espnow_recv_cb(const esp_now_recv_info_t *recv_info,
                                   const uint8_t *data, int len) {
  if (s_example_espnow_queue) {
    espnow_recv_data_t *rec_data = (espnow_recv_data_t *)data;

    if (memcmp(rec_data->desc_mac, local_node_mac, 6) == 0) {
      memcpy(rec_data->desc_mac, root_mac, 6);
      rec_data->data[0] = 0;
      rec_data->size = 1;
      esp_now_send(root_mac, data, 16);
    } else if (memcmp(rec_data->desc_mac, root_mac, 6) == 0) {
      // ESP_LOGI(TAG, "send to root %ld", rec_data->magic);
      esp_now_send(root_mac, data, len);
    } else if (memcmp(rec_data->desc_mac, node_mac, 6) == 0) {
      // ESP_LOGI(TAG, "send to node %ld", rec_data->magic);
      esp_now_send(node_mac, data, len);
    }
  }
}

static void example_espnow_task(void *pvParameter) {
  espnow_recv_data_t device_pkg = {0};
  while (true) {
    if (s_example_espnow_queue &&
        xQueueReceive(s_example_espnow_queue, &device_pkg, portMAX_DELAY) ==
            pdTRUE) {
    }
  }
}

static esp_err_t example_espnow_init(void) {
  example_espnow_send_param_t *send_param;

  s_example_espnow_queue =
      xQueueCreate(ESPNOW_QUEUE_SIZE, sizeof(example_espnow_event_t));
  if (s_example_espnow_queue == NULL) {
    ESP_LOGE(TAG, "Create mutex fail");
    return ESP_FAIL;
  }

  /* Initialize ESPNOW and register sending and receiving callback function. */
  ESP_ERROR_CHECK(esp_now_init());
  ESP_ERROR_CHECK(esp_now_register_recv_cb(example_espnow_recv_cb));

  /* Add broadcast peer information to peer list. */
  esp_now_peer_info_t *peer = malloc(sizeof(esp_now_peer_info_t));
  if (peer == NULL) {
    ESP_LOGE(TAG, "Malloc peer information fail");
    vSemaphoreDelete(s_example_espnow_queue);
    esp_now_deinit();
    return ESP_FAIL;
  }
  memset(peer, 0, sizeof(esp_now_peer_info_t));
  peer->channel = CONFIG_ESPNOW_CHANNEL;
  peer->ifidx = ESPNOW_WIFI_IF;
  peer->encrypt = false;
  memcpy(peer->peer_addr, root_mac, ESP_NOW_ETH_ALEN);
  ESP_ERROR_CHECK(esp_now_add_peer(peer));
  memcpy(peer->peer_addr, node_mac, ESP_NOW_ETH_ALEN);
  ESP_ERROR_CHECK(esp_now_add_peer(peer));
  free(peer);

  xTaskCreate(example_espnow_task, "example_espnow_task", 2048, NULL, 4, NULL);

  return ESP_OK;
}

static void example_espnow_deinit(example_espnow_send_param_t *send_param) {
  free(send_param->buffer);
  free(send_param);
  vSemaphoreDelete(s_example_espnow_queue);
  esp_now_deinit();
}

void app_main(void) {
  // Initialize NVS
  esp_err_t ret = nvs_flash_init();
  if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
      ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
    ESP_ERROR_CHECK(nvs_flash_erase());
    ret = nvs_flash_init();
  }

  ESP_ERROR_CHECK(ret);

  example_wifi_init();
  example_espnow_init();
  //  读取本地MAC地址
  esp_wifi_get_mac(ESP_IF_WIFI_STA, local_node_mac);
}
